package com.tank.thread;

import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Set;

import com.tank.entity.Brick;
import com.tank.entity.GameResource;
import com.tank.entity.Iron;
import com.tank.entity.Position;
import com.tank.entity.RobotTank;
import com.tank.entity.Tank;
import com.tank.entity.Water;
import com.tank.response.TankLocationResponse;
import com.tank.server.handler.TankServer;

import io.netty.channel.Channel;

public class RobotRouteThread2 extends Thread {
	private GameResource resource;
	private Tank tank;
	private RobotTank robot;
	private Position circleCenterPosition;
	private Channel channel;

	public RobotRouteThread2(String roomId, String tankId, String robotId) {
		this.resource = TankServer.RESOURCE.get(roomId);
		this.tank = resource.getPlayerTanks().get(tankId);
		this.robot = resource.getRobotTanks().get(robotId);
		this.circleCenterPosition = new Position(robot.getCircleCenterX(), robot.getCircleCenterY());
		this.channel=TankServer.ROOM_CHANNELGROUP.get(roomId).get(tankId);
	}

	@Override
	public void run() {
		LinkedList<Tank> routes = findRoute(robot, tank);
		drawRoute(routes);
	}

	public void drawRoute(LinkedList<Tank> routes) {
		// 机器坦克沿着规划路线走
		for (Tank route : routes) {
			try {
				Thread.sleep(30);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			// 判断：如果沿着规划的路线继续走，会不会跑出警戒范围，如果会，则不走规划的路线
			if (hEuclidianDistance(circleCenterPosition, route) > RobotTank.WARNRANGE) {
				break;
			}
			boolean crash = false; // 机器坦克在规划的路线上发生碰撞
			for (Tank t : resource.getRobotTanks().values()) { // 判断机器坦克是否与其他机器坦克重叠
				if (!robot.getTankId().equals(t.getTankId())) {
					if (robot.Overlap(t) && t.isAlive()) { // 有可能坦克死了，但是子弹仍然显示在界面上，坦克未被移除
						crash = true;
						break;
					}
				}
			}
			for (Tank t : resource.getPlayerTanks().values()) { // 判断机器坦克是否与玩家坦克重叠
				if (robot.Overlap(t) && t.isAlive()) { // 有可能坦克死了，但是子弹仍然显示在界面上，坦克未被移除
					crash = true;
					break;
				}
			}
			if (crash == true) { // 在路径上碰撞的话，不再继续走
				break;
			}
			robot.setX(route.getX());
			robot.setY(route.getY());
			robot.setDirect(route.getDirect());
			// 发送位置信息
			TankLocationResponse tankLocationResponse = new TankLocationResponse();
			tankLocationResponse.setTankId(robot.getTankId());
			tankLocationResponse.setX(robot.getX());
			tankLocationResponse.setY(robot.getY());
			tankLocationResponse.setDirect(robot.getDirect());
			// TankServer.ROOM_CHANNELGROUP.get(roomId).get(channelId).writeAndFlush(tankLocationResponse);
			channel.writeAndFlush(tankLocationResponse);

			for (Tank t : resource.getPlayerTanks().values()) {
				if (Math.abs(t.getX() - robot.getX()) < robot.getWidth() / 2 && t.getY() < robot.getY()) { // 如果机器坦克在下面
					boolean ironFlag = false; // 路径中是否有钢铁的标识
					for (Iron iron : resource.getIrons()) { // 子弹路径上，不会有钢铁
						if (Math.abs(iron.getX() - robot.getX()) < iron.getWidth() / 2 && iron.getY() < robot.getY()
								&& iron.getY() > t.getY()) {
							ironFlag = true;
							break;
						}
					}
					if (ironFlag == false) {
						robot.setDirect(Tank.NORTH);
						synchronized (robot.getRemainBulletCount()) {
							if (robot.getRemainBulletCount() > 0) {
								// Bullet bullet = robot.shot();
								// Thread thread = new Thread(new
								// BulletRepaintThread(bullet,
								// robot));
								// thread.start();
							}
						}

					}
				} else if (Math.abs(t.getX() - robot.getX()) < robot.getWidth() / 2 && t.getY() > robot.getY()) { // 如果机器坦克在上面
					boolean ironFlag = false; // 路径中是否有钢铁的标识
					for (Iron iron : resource.getIrons()) { // 子弹路径上，不会有钢铁
						if (Math.abs(iron.getX() - robot.getX()) < iron.getWidth() / 2 && iron.getY() > robot.getY()
								&& iron.getY() < t.getY()) {
							ironFlag = true;
							break;
						}
					}
					if (ironFlag == false) {
						robot.setDirect(Tank.SOUTH);
						synchronized (robot.getRemainBulletCount()) {
							if (robot.getRemainBulletCount() > 0) {
								// Bullet bullet = robot.shot();
								// Thread thread = new Thread(new
								// BulletRepaintThread(bullet,
								// robot));
								// thread.start();
							}
						}
					}
				} else if (Math.abs(t.getY() - robot.getY()) < robot.getWidth() / 2 && t.getX() > robot.getX()) { // 如果机器坦克在左边
					boolean ironFlag = false; // 路径中是否有钢铁的标识
					for (Iron iron : resource.getIrons()) { // 子弹路径上，不会有钢铁
						if (Math.abs(iron.getY() - robot.getY()) < iron.getWidth() / 2 && iron.getX() > robot.getX()
								&& iron.getX() < t.getX()) {
							ironFlag = true;
							break;
						}
					}
					if (ironFlag == false) {
						robot.setDirect(Tank.EAST);
						synchronized (robot.getRemainBulletCount()) {
							if (robot.getRemainBulletCount() > 0) {
								// Bullet bullet = robot.shot();
								// Thread thread = new Thread(new
								// BulletRepaintThread(bullet,
								// robot));
								// thread.start();
							}
						}
					}
				} else if (Math.abs(t.getY() - robot.getY()) < robot.getWidth() / 2 && t.getX() < robot.getX()) { // 如果机器坦克在右边
					boolean ironFlag = false; // 路径中是否有钢铁的标识
					for (Iron iron : resource.getIrons()) { // 子弹路径上，不会有钢铁
						if (Math.abs(iron.getY() - robot.getY()) < iron.getWidth() / 2 && iron.getX() < robot.getX()
								&& iron.getX() > t.getX()) {
							ironFlag = true;
							break;
						}
					}
					if (ironFlag == false) {
						robot.setDirect(Tank.WEST);
						synchronized (robot.getRemainBulletCount()) {
							if (robot.getRemainBulletCount() > 0) {
								// Bullet bullet = robot.shot();
								// Thread thread = new Thread(new
								// BulletRepaintThread(bullet,
								// robot));
								// thread.start();
							}
						}
					}
				}
			}
		}

	}

	/**
	 * 寻路
	 * 
	 * @param startTank
	 * @param endTank
	 */
	public LinkedList<Tank> findRoute(Tank startTank, Tank endTank) {
		Set<Position> closeTable = new HashSet<>(); // closed表
		Comparator<Position> comp = new Comparator<Position>() {

			@Override
			public int compare(Position p1, Position p2) {
				return new Double(p1.getF()).compareTo(new Double(p2.getF()));
			}
		};
		PriorityQueue<Position> opentable = new PriorityQueue<>(comp); // open表
		Position startPosition = new Position(startTank.getX(), startTank.getY()); // 起始点
		Position endPosition = new Position(endTank.getX(), endTank.getY()); // 终点
		int speed = startTank.getSpeed(); // 坦克的移动速度
		startPosition.setDirect(startTank.getDirect());
		startPosition.setH(h(startPosition, endPosition));
		startPosition.setG(0);
		startPosition.setF(h(startPosition, endPosition));
		opentable.add(startPosition);

		boolean finish = false; // 寻路结束的标识
		final int[][] directs = { { 0, -speed }, { 0, speed }, { -speed, 0 }, { speed, 0 } }; // 可以扩展的四个方向
		Position lastPosition = null;
		List<Brick> bricks = resource.getBricks();
		List<Water> waters = resource.getWaters();
		List<Iron> irons = resource.getIrons();
		while (!opentable.isEmpty() && !finish) {
			Position p = opentable.poll(); // 取f最小的节点进行扩展
			closeTable.add(p); // 将已扩展的节点放入closed表
			for (int direct = 0; direct < 4; direct++) { // 判断坦克往四个方向会不会碰到障碍物，如果会碰撞就不进行扩展

				Position newPosition = new Position(p.getX() + directs[direct][0], p.getY() + directs[direct][1]);
				Tank robot = new Tank(p.getX(), p.getY(), direct, "");
				// 如果坦克的下一步，没有跑出地图
				if (newPosition.getX() >= 20 && newPosition.getX() <= 600 - 20 && newPosition.getY() >= 20
						&& newPosition.getY() < 600 - 20 && !closeTable.contains(newPosition)
						&& !opentable.contains(newPosition)) {
					// 如果已将到达终点,也就是和目标坦克发生碰撞,并且发射子弹能击中终点坦克
					// if (robot.Overlap(endTank) && (Math.abs(endTank.getX() -
					// robot.getX()) < robot.getWidth() / 2
					// || Math.abs(endTank.getY() - robot.getY()) <
					// robot.getWidth() / 2)) {
					// lastPosition = p;
					// // lastPosition.setLast(p);
					// finish = true;
					// break;
					// }
					if (robot.Overlap(endTank)) {
						lastPosition = p;
						// lastPosition.setLast(p);
						finish = true;
						break;
					}
					// 判断robot往direct方向走，会不会碰到砖块、水或者钢铁，如果会碰撞，该direct的下一个坐标就不进行扩展
					for (int j = 0; j < bricks.size(); j++) { // 判断我的坦克是否与砖块重叠
						if (robot.Overlap(bricks.get(j)) == true) {
							robot.setCrash(true);
							break;
						}
					}
					for (int j = 0; j < irons.size(); j++) { // 判断我的坦克是否与铁块重叠
						if (robot.Overlap(irons.get(j)) == true) {
							robot.setCrash(true);
							break;
						}
					}
					for (int j = 0; j < waters.size(); j++) { // 判断我的坦克是否与河流重叠
						if (robot.Overlap(waters.get(j)) == true) {
							robot.setCrash(true);
							break;
						}
					}
					if (robot.isCrash()) { // 如果坦克在该坐标，该方向的下一个扩展点会发生碰撞，则该扩展点无效
						continue;
					} else {
						newPosition.setDirect(direct);
						newPosition.setLast(p);
						newPosition.setG(p.getG() + speed);
						newPosition.setH(h(newPosition, endPosition));
						newPosition.setF(newPosition.getH() + newPosition.getG());
						opentable.add(newPosition); // 最小的耗散值的节点进入open表
					}
				}
			}
		}
		LinkedList<Tank> route = new LinkedList<>();
		while (lastPosition != null) {
			Tank t = new Tank(lastPosition.getX(), lastPosition.getY(), lastPosition.getDirect(),
					startTank.getTankId());
			route.addFirst(t);
			lastPosition = lastPosition.getLast();
		}
		return route;
	}

	double h(Position pnt, Position endPosition) {
		return hEuclidianDistance(pnt, endPosition);
	}

	/**
	 * 欧式距离,小于等于实际值
	 */
	double hEuclidianDistance(Position endPosition, Tank pnt) {
		return Math.sqrt(Math.pow(pnt.getX() - endPosition.getX(), 2) + Math.pow(pnt.getY() - endPosition.getY(), 2));
	}

	/**
	 * 欧式距离,小于等于实际值
	 */
	double hEuclidianDistance(Tank tank1, Tank tank2) {
		return Math.sqrt(Math.pow(tank1.getX() - tank2.getX(), 2) + Math.pow(tank1.getY() - tank2.getY(), 2));
	}

	/**
	 * 欧式距离,小于等于实际值
	 */
	double hEuclidianDistance(Position pnt, Position endPosition) {
		return Math.sqrt(Math.pow(pnt.getX() - endPosition.getX(), 2) + Math.pow(pnt.getY() - endPosition.getY(), 2));
	}
}
